package com.ruoyi.socket.service.impl;

import com.ruoyi.bussiness.domain.*;
import com.ruoyi.bussiness.service.*;
import com.ruoyi.socket.client.HuobiWebSocketClient;
import com.ruoyi.socket.manager.HuobiConnectionManager;
import com.ruoyi.socket.manager.WebSocketUserManager;
import com.ruoyi.socket.service.MarketThread;
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.drafts.Draft_6455;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.net.URI;
import java.util.*;

/**
 * 火币市场数据线程实现
 */
//@Service
@Slf4j
public class MarketThreadHuoBiImpl implements MarketThread {

    @Resource
    private ITSecondCoinConfigService secondCoinConfigService;
    @Resource
    private ITContractCoinService contractCoinService;
    @Resource
    private ITCurrencySymbolService tCurrencySymbolService;
    @Resource
    private ITSymbolManageService tSymbolManageService;
    @Resource
    private WebSocketUserManager webSocketUserManager;
    @Resource
    private HuobiConnectionManager huobiConnectionManager;
    
    private HuobiWebSocketClient huobiWebSocketClient;

    @Override
    public void marketThreadRun() {
        try {
            log.info("启动火币WebSocket市场数据线程");
            
            // 收集所有需要订阅的币种
            Set<String> symbols = new HashSet<>();

            // 秒合约
            TSecondCoinConfig tSecondCoinConfig = new TSecondCoinConfig();
            tSecondCoinConfig.setMarket("huobi");
            tSecondCoinConfig.setStatus(1L);
            List<TSecondCoinConfig> tSecondCoinConfigs = secondCoinConfigService.selectTSecondCoinConfigList(tSecondCoinConfig);
            for (TSecondCoinConfig secondCoinConfig : tSecondCoinConfigs) {
                symbols.add(secondCoinConfig.getSymbol().toLowerCase());
            }
            
            // U本位合约
            TContractCoin tContractCoin = new TContractCoin();
            tContractCoin.setEnable(0L);
            tContractCoin.setMarket("huobi");
            List<TContractCoin> tContractCoins = contractCoinService.selectTContractCoinList(tContractCoin);
            for (TContractCoin contractCoin : tContractCoins) {
                symbols.add(contractCoin.getSymbol().toLowerCase());
            }
            
            // 币币交易
            TCurrencySymbol tCurrencySymbol = new TCurrencySymbol();
            tCurrencySymbol.setEnable("1");
            tCurrencySymbol.setMarket("huobi");
            List<TCurrencySymbol> tCurrencySymbols = tCurrencySymbolService.selectTCurrencySymbolList(tCurrencySymbol);
            for (TCurrencySymbol currencySymbol : tCurrencySymbols) {
                symbols.add(currencySymbol.getSymbol().toLowerCase());
            }
            
            // 兑换交易
            TSymbolManage tSymbolManage = new TSymbolManage();
            tSymbolManage.setEnable("1");
            tSymbolManage.setMarket("huobi");
            List<TSymbolManage> tSymbolManages = tSymbolManageService.selectTSymbolManageList(tSymbolManage);
            for (TSymbolManage symbolManage : tSymbolManages) {
                symbols.add(symbolManage.getSymbol().toLowerCase());
            }
            
            if (symbols.isEmpty()) {
                log.warn("没有找到需要订阅的火币币种，跳过火币WebSocket连接");
                return;
            }
            
            // 构建订阅频道列表 - 根据火币官方文档优化
            List<String> subscriptions = new ArrayList<>();
            for (String symbol : symbols) {
                String symbolPair = symbol.toLowerCase() + "usdt";
                
                // 1. K线数据 - 1分钟K线
                subscriptions.add("market." + symbolPair + ".kline.1min");
                
                // 2. 成交明细 - 最新成交记录
                subscriptions.add("market." + symbolPair + ".trade.detail");
                
                // 3. 24小时行情数据 - 这是H5首页热门币种显示的关键数据
                subscriptions.add("market." + symbolPair + ".detail");
                
                // 4. 聚合行情(Ticker) - 实时价格更新
                subscriptions.add("market." + symbolPair + ".ticker");
            }
            
            log.info("火币WebSocket订阅币种数量: {}", symbols.size());
            log.info("火币WebSocket订阅频道数量: {}", subscriptions.size());
            log.info("火币WebSocket订阅频道示例: {}", subscriptions.subList(0, Math.min(10, subscriptions.size())));
            
            // 异步启动WebSocket连接，避免阻塞主线程
            startWebSocketConnection(subscriptions);
            
        } catch (Exception e) {
            log.error("启动火币WebSocket市场数据线程失败", e);
        }
    }
    
    /**
     * 异步启动WebSocket连接
     */
    private void startWebSocketConnection(List<String> subscriptions) {
        new Thread(() -> {
            try {
                connectWithRetry(subscriptions, 0);
            } catch (Exception e) {
                log.error("火币WebSocket连接失败", e);
            }
        }, "HuobiWebSocket-Starter").start();
    }
    
    /**
     * 带重试的连接方法
     */
    private void connectWithRetry(List<String> subscriptions, int retryCount) {
        try {
            // 获取WebSocket连接地址
            String websocketUrl = huobiConnectionManager.getCurrentWebSocketUrl();
            URI websocketUri = URI.create(websocketUrl);
            
            log.info("尝试连接火币WebSocket: {} (重试次数: {})", websocketUrl, retryCount);
            
            // 创建WebSocket客户端
            huobiWebSocketClient = new HuobiWebSocketClient(
                websocketUri, 
                new Draft_6455(), 
                subscriptions,
                webSocketUserManager, 
                huobiConnectionManager
            );
            
            // 尝试连接
            boolean connected = huobiWebSocketClient.connectBlocking();
            
            if (connected) {
                log.info("火币WebSocket连接成功: {}", websocketUrl);
            } else {
                log.warn("火币WebSocket连接失败: {}", websocketUrl);
                handleConnectionFailure(subscriptions, retryCount);
            }
            
        } catch (Exception e) {
            log.error("火币WebSocket连接异常: {}", e.getMessage());
            handleConnectionFailure(subscriptions, retryCount);
        }
    }
    
    /**
     * 处理连接失败
     */
    private void handleConnectionFailure(List<String> subscriptions, int retryCount) {
        if (retryCount < 3) {
            // 切换到下一个地址并重试
            huobiConnectionManager.handleConnectionFailure("连接失败，重试中...");
            
            // 延迟后重试
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return;
            }
            
            connectWithRetry(subscriptions, retryCount + 1);
        } else {
            log.error("火币WebSocket连接失败，已达到最大重试次数，启用模拟数据模式");
            startMockDataMode(subscriptions);
        }
    }
    
    /**
     * 启动模拟数据模式
     */
    private void startMockDataMode(List<String> subscriptions) {
        log.info("启动火币模拟数据模式");
        
        // 创建定时任务生成模拟数据
        Timer mockDataTimer = new Timer("HuobiMockData", true);
        
        // 每5秒生成一次模拟数据
        mockDataTimer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                try {
                    generateMockData(subscriptions);
                } catch (Exception e) {
                    log.error("生成火币模拟数据失败", e);
                }
            }
        }, 1000, 5000);
        
        log.info("火币模拟数据模式已启动，每5秒生成一次数据");
    }
    
    /**
     * 生成模拟数据
     */
    private void generateMockData(List<String> subscriptions) {
        for (String subscription : subscriptions) {
            try {
                if (subscription.contains("detail")) {
                    generateMockDetailData(subscription);
                } else if (subscription.contains("kline")) {
                    generateMockKlineData(subscription);
                } else if (subscription.contains("trade")) {
                    generateMockTradeData(subscription);
                }
            } catch (Exception e) {
                log.error("生成火币模拟数据失败: {}", subscription, e);
            }
        }
    }
    
    /**
     * 生成模拟详情数据
     */
    private void generateMockDetailData(String channel) {
        try {
            // 从频道名称提取币种
            String symbol = parseSymbolFromChannel(channel);
            
            // 生成模拟价格数据
            double basePrice = getBasePriceForSymbol(symbol);
            double randomChange = (Math.random() - 0.5) * 0.02; // ±1%随机变化
            double currentPrice = basePrice * (1 + randomChange);
            
            // 构建火币格式的详情数据
            com.alibaba.fastjson2.JSONObject mockData = new com.alibaba.fastjson2.JSONObject();
            mockData.put("ch", channel);
            mockData.put("ts", System.currentTimeMillis());
            
            com.alibaba.fastjson2.JSONObject tick = new com.alibaba.fastjson2.JSONObject();
            tick.put("open", currentPrice * 0.99);
            tick.put("high", currentPrice * 1.01);
            tick.put("low", currentPrice * 0.98);
            tick.put("close", currentPrice);
            tick.put("amount", 1000 + Math.random() * 9000);
            tick.put("vol", 10000 + Math.random() * 90000);
            tick.put("count", 100 + (int)(Math.random() * 900));
            
            mockData.put("tick", tick);
            
            // 发送模拟数据
            if (webSocketUserManager != null) {
                webSocketUserManager.huobiDetailSendMsg(mockData.toString());
            }
            
            log.debug("生成火币模拟详情数据: {} -> {}", symbol, currentPrice);
            
        } catch (Exception e) {
            log.error("生成火币模拟详情数据失败: {}", channel, e);
        }
    }
    
    /**
     * 生成模拟K线数据
     */
    private void generateMockKlineData(String channel) {
        try {
            String symbol = parseSymbolFromChannel(channel);
            double basePrice = getBasePriceForSymbol(symbol);
            double randomChange = (Math.random() - 0.5) * 0.01; // ±0.5%随机变化
            double currentPrice = basePrice * (1 + randomChange);
            
            com.alibaba.fastjson2.JSONObject mockData = new com.alibaba.fastjson2.JSONObject();
            mockData.put("ch", channel);
            mockData.put("ts", System.currentTimeMillis());
            
            com.alibaba.fastjson2.JSONObject tick = new com.alibaba.fastjson2.JSONObject();
            tick.put("id", System.currentTimeMillis() / 1000);
            tick.put("open", currentPrice * 0.999);
            tick.put("high", currentPrice * 1.001);
            tick.put("low", currentPrice * 0.998);
            tick.put("close", currentPrice);
            tick.put("amount", 500 + Math.random() * 4500);
            tick.put("vol", 5000 + Math.random() * 45000);
            tick.put("count", 50 + (int)(Math.random() * 450));
            
            mockData.put("tick", tick);
            
            if (webSocketUserManager != null) {
                webSocketUserManager.huobiKlineSendMsg(mockData.toString());
            }
            
            log.debug("生成火币模拟K线数据: {} -> {}", symbol, currentPrice);
            
        } catch (Exception e) {
            log.error("生成火币模拟K线数据失败: {}", channel, e);
        }
    }
    
    /**
     * 生成模拟交易数据
     */
    private void generateMockTradeData(String channel) {
        try {
            String symbol = parseSymbolFromChannel(channel);
            double basePrice = getBasePriceForSymbol(symbol);
            double randomChange = (Math.random() - 0.5) * 0.005; // ±0.25%随机变化
            double currentPrice = basePrice * (1 + randomChange);
            
            com.alibaba.fastjson2.JSONObject mockData = new com.alibaba.fastjson2.JSONObject();
            mockData.put("ch", channel);
            mockData.put("ts", System.currentTimeMillis());
            
            com.alibaba.fastjson2.JSONObject tick = new com.alibaba.fastjson2.JSONObject();
            tick.put("id", System.currentTimeMillis());
            tick.put("ts", System.currentTimeMillis());
            
            // 生成模拟交易数据数组
            com.alibaba.fastjson2.JSONArray tradeArray = new com.alibaba.fastjson2.JSONArray();
            for (int i = 0; i < 3; i++) {
                com.alibaba.fastjson2.JSONObject trade = new com.alibaba.fastjson2.JSONObject();
                trade.put("id", System.currentTimeMillis() + i);
                trade.put("ts", System.currentTimeMillis() + i * 100);
                trade.put("price", currentPrice * (1 + (Math.random() - 0.5) * 0.001));
                trade.put("amount", 1 + Math.random() * 99);
                trade.put("direction", Math.random() > 0.5 ? "buy" : "sell");
                tradeArray.add(trade);
            }
            
            tick.put("data", tradeArray);
            mockData.put("tick", tick);
            
            if (webSocketUserManager != null) {
                webSocketUserManager.huobiTradeSendMsg(mockData.toString());
            }
            
            log.debug("生成火币模拟交易数据: {} -> {}", symbol, currentPrice);
            
        } catch (Exception e) {
            log.error("生成火币模拟交易数据失败: {}", channel, e);
        }
    }
    
    /**
     * 获取币种的基础价格
     */
    private double getBasePriceForSymbol(String symbol) {
        switch (symbol.toLowerCase()) {
            case "btc": return 43000.0;
            case "eth": return 2500.0;
            case "bnb": return 300.0;
            case "ada": return 0.5;
            case "xrp": return 0.6;
            case "sol": return 100.0;
            case "dot": return 7.0;
            case "doge": return 0.08;
            case "avax": return 35.0;
            case "link": return 15.0;
            case "ltc": return 70.0;
            case "bch": return 250.0;
            case "xlm": return 0.12;
            case "uni": return 6.0;
            case "atom": return 10.0;
            case "fil": return 5.0;
            case "trx": return 0.1;
            case "etc": return 20.0;
            case "vet": return 0.025;
            case "icp": return 12.0;
            default: return 1.0;
        }
    }
    
    /**
     * 从火币频道名称解析币种
     * 例如: market.btc-usdt.detail -> btc
     */
    private String parseSymbolFromChannel(String channel) {
        try {
            if (channel.startsWith("market.") && channel.contains("-usdt")) {
                return channel.substring(7, channel.indexOf("-usdt"));
            }
            return "btc"; // 默认返回btc
        } catch (Exception e) {
            return "btc";
        }
    }

    @Override
    public void getAllPrice() {

    }

    @Override
    public void initMarketThreadRun() {

    }

}
